use criterion::{black_box, criterion_group, criterion_main, Criterion};
use set::set::{Set, SetHashFunc, SetEqualFunc};

fn set_contains_benchmark(c: &mut Criterion) {
    let hash_func: SetHashFunc<i32> = |data| *data as u64;
    let equal_func: SetEqualFunc<i32> = |a, b| a == b;
    let mut set = Set::new(hash_func, equal_func).unwrap();

    for i in 0..1000 {
        set.insert(i);
    }

    c.bench_function("set_contains", |b| {
        b.iter(|| set.contains(black_box(&500)))
    });
}

fn set_insert_benchmark(c: &mut Criterion) {
    let hash_func: SetHashFunc<i32> = |data| *data as u64;
    let equal_func: SetEqualFunc<i32> = |a, b| a == b;
    let mut set = Set::new(hash_func, equal_func).unwrap();

    c.bench_function("set_insert", |b| {
        b.iter(|| set.insert(black_box(1000)))
    });
}

fn set_remove_benchmark(c: &mut Criterion) {
    let hash_func: SetHashFunc<i32> = |data| *data as u64;
    let equal_func: SetEqualFunc<i32> = |a, b| a == b;
    let mut set = Set::new(hash_func, equal_func).unwrap();

    for i in 0..1000 {
        set.insert(i);
    }

    c.bench_function("set_remove", |b| {
        b.iter(|| set.remove(black_box(&500)))
    });
}

fn set_union_benchmark(c: &mut Criterion) {
    let hash_func: SetHashFunc<i32> = |data| *data as u64;
    let equal_func: SetEqualFunc<i32> = |a, b| a == b;
    let mut set1 = Set::new(hash_func, equal_func).unwrap();
    let mut set2 = Set::new(hash_func, equal_func).unwrap();

    for i in 0..1000 {
        set1.insert(i);
        set2.insert(i + 500);
    }

    c.bench_function("set_union", |b| {
        b.iter(|| Set::union(black_box(&set1), black_box(&set2)))
    });
}

fn set_intersection_benchmark(c: &mut Criterion) {
    let hash_func: SetHashFunc<i32> = |data| *data as u64;
    let equal_func: SetEqualFunc<i32> = |a, b| a == b;
    let mut set1 = Set::new(hash_func, equal_func).unwrap();
    let mut set2 = Set::new(hash_func, equal_func).unwrap();

    for i in 0..1000 {
        set1.insert(i);
        set2.insert(i + 500);
    }

    c.bench_function("set_intersection", |b| {
        b.iter(|| Set::intersection(black_box(&set1), black_box(&set2)))
    });
}

criterion_group!(
    benches,
    set_contains_benchmark,
    set_insert_benchmark,
    set_remove_benchmark,
    set_union_benchmark,
    set_intersection_benchmark
);
criterion_main!(benches);